package com.mbbmap.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;

/**
 * <code>DateUtil</code> is a utility class that is used to:
 * <ul>
 *    <li>Convert a <code>String</code> to a <code>Date</code>
 *    <li>Convert a <code>Date</code> to a <code>String</code>
 *    <li>Extract the "date"/"month"/"year" portion of a <code>Date</code> as a <code>String</code>
 *    <li>Create a <code>Date</code> that represents "now"
 *    <li>Create a <code>Date</code> that represents "today" (time portion is zero)
 *    <li>Get a <code>Date</code> that represents "tomorrow" of a date (time portion is zero)
 *    <li>Get a <code>Date</code> that represents "yesterday" of a date (time portion is zero)
 *    <li>Remove the time portion of a date (make it zero)
 * </ul>
 */
public class DateUtil {

    /**
     * Formats a date using the pattern "dd/MM/yyyy"
     *
     * @param   date  A date to format
     * @return      The date as a string
     */
  public static String formatLocalSlash(Date date) {
    return DateFormatUtils.format(date, "dd/MM/yyyy");
  }

  public static String formatLocalSlashShortYear(Date date) {
    return DateFormatUtils.format(date, "dd/MM/yy");
  }

  public static String formatLocalDashShortYear(Date date) {
    return DateFormatUtils.format(date, "dd-MM-yy");
  }

  public static String formatHoursMinutesSeconds(Date date) {
    return DateFormatUtils.format(date, "HH:mm:ss");
  }

  public static String formatHoursMinutes(Date date) {
    return DateFormatUtils.format(date, "HH:mm");
  }

  public static String formatHoursMinutesAMPM(Date date) {
    return DateFormatUtils.format(date, "h:mm a");
  }
    /**
     * Formats a date using the pattern "yyyy-MM-dd"
     *
     * @param   date  A date to format
     * @return      The date as a string
     */
  public static String formatDateTimeDash(Date date) {
    return DateFormatUtils.format(date, "yyyy-MM-dd HH:mm:ss a");
  }

    /**
     * Formats a date using the pattern "dd-MM-yyyy"
     *
     * @param   date  A date to format
     * @return      The date as a string
     */
  public static String formatLocalDash(Date date) {
    return DateFormatUtils.format(date, "dd-MM-yyyy");
  }

    /**
     * Formats a date using the pattern "yyyyMMdd"
     *
     * @param   date  A date to format
     * @return      The date as a string
     */
  public static String formatUniversal(Date date) {
    return DateFormatUtils.format(date, "yyyyMMdd");
  }

  public static String format(Date date, String format) {
    return DateFormatUtils.format(date, format);
  }

  public static String formatMonthAndYear(Date date) {
    return DateFormatUtils.format(date, "MMMMM ''yy");
  }

    /**
     * Extracts the date portion of a <code>Date</code> object using the pattern "dd".
     * <p>
     * E.g.<br>
     * getDateOptionValue of 2nd March 2004 will return "02".<br>
     * getDateOptionValue of 12th November 1999 will return "12".
     *
     * @param   date  A date to format
     * @return      The date portion as a string
     */
  public static String getDateOptionValue(Date date) {
    return DateFormatUtils.format(date, "dd");
  }

    /**
     * Extracts the month portion of a <code>Date</code> object using the pattern "MM".
     * <p>
     * E.g.<br>
     * getDateOptionValue of 2nd March 2004 will return "03".<br>
     * getDateOptionValue of 12th November 1999 will return "11".
     *
     * @param   date  A date to format
     * @return      The month portion as a string
     */
  public static String getMonthOptionValue(Date date) {
    return DateFormatUtils.format(date, "MM");
  }

    /**
     * Extracts the year portion of a <code>Date</code> object using the pattern "yyyy".
     * <p>
     * E.g.<br>
     * <code>getDateOptionValue</code> of 2nd Feb 2004 will return "2004".<br>
     * <code>getDateOptionValue</code> of 12th March 1999 will return "1999".
     *
     * @param   date  A date to format
     * @return      The year portion as a string
     */
  public static String getYearOptionValue(Date date) {
    return DateFormatUtils.format(date, "yyyy");
  }

    /**
     * Creates a <code>Date</code> object from a string representation of a date (with the pattern "yyyyMMdd").
     *
     * @param   dateStr     The date string
     * @return          A <code>Date</code> object that represents the date implied in the string
     * @throws  ParseException  If the date string is not valid
     */
  public static Date createDateUniversal(String dateStr) throws ParseException {
    SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
    formatter.setLenient(false);
    return formatter.parse(dateStr);
  }



    /**
     * Creates a <code>Date</code> object from a string representation of a date (with the pattern "dd/MM/yy HH:mm:ss").
     *
     * @param   dateStr     The date string
     * @return          A <code>Date</code> object that represents the date implied in the string
     * @throws  ParseException  If the date string is not valid
     */
  public static Date createDateTimeSlash(String dateStr) throws ParseException {
    SimpleDateFormat formatter;
    if (dateStr.length() < 19){
        formatter = new SimpleDateFormat("dd/MM/yy HH:mm:ss");
    } else {
        formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    }
    formatter.setLenient(false);
    return formatter.parse(dateStr);
  }
  
  public static Date createDateTimeSlashType(String dateStr) throws ParseException {
	    SimpleDateFormat formatter;
	    if (dateStr.length() < 19){
	        formatter = new SimpleDateFormat("yy-mm-dd HH:mm:ss");
	    } else {
	        formatter = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
	    }
	    formatter.setLenient(false);
	    return formatter.parse(dateStr);
	  }

    /**
     * Creates a <code>Date</code> object from a string representation of a date (with the pattern "dd/MM/yyyy").
     *
     * @param   dateStr     The date string
     * @return          A <code>Date</code> object that represents the date implied in the string
     * @throws  ParseException  If the date string is not valid
     */
  public static Date createDateLocalSlash(String dateStr) throws ParseException {
    SimpleDateFormat formatter;
    if (dateStr.length() < 10){
        formatter = new SimpleDateFormat("dd/MM/yy");
    } else{
        formatter = new SimpleDateFormat("dd/MM/yyyy");
    }
    formatter.setLenient(false);
    return formatter.parse(dateStr);
  }

    /**
     * Creates a <code>Date</code> object from a string representation of a date (with the pattern "dd-MM-yyyy").
     *
     * @param   dateStr     The date string
     * @return          A <code>Date</code> object that represents the date implied in the string
     * @throws  ParseException  If the date string is not valid
     */
  public static Date createDateLocalDash(String dateStr) throws ParseException {
    SimpleDateFormat formatter;
    if (dateStr.length() < 10){
	    formatter = new SimpleDateFormat("dd-MM-yy");
    } else{
        formatter = new SimpleDateFormat("dd-MM-yyyy");
    }
    formatter.setLenient(false);
    return formatter.parse(dateStr);
  }

    /**
     * Creates a <code>Date</code> object from a 3 <code>String</code> params representing the date, month and year
     * respectively.
     *
     * @param   date      The date portion. Valid dates are from "0" (or "00"), "1" (or "01") and so forth until "31".
     * @param   month     The month portion. Valid months are from "01" (representing Jan) to "12" (representing Dec).
     * @param   year      The year portion.
     *
     * @return          A <code>Date</code> object that represents the date implied in the params
     *
     * @throws  ParseException If the date params are not valid
     */
  public static Date createDateLocal(String date, String month, String year) throws ParseException {
    date = StringUtils.leftPad(date, 2, '0');
    month = StringUtils.leftPad(month, 2, '0');
    String fullDate = date + "/" + month + "/" + year;

    return createDateLocalSlash(fullDate);
  }


    /**
     * Creates a <code>Date</code> object from a 3 int params representing the date, month and year
     * respectively.
     *
     * @param   date      The date portion. Valid dates are from 0 to 31.
     * @param   month     The month portion. Valid months are from 1 (representing Jan) to 12 (representing Dec).
     * @param   year      The year portion.
     *
     * @return          A <code>Date</code> object that represents the date implied in the params
     *
     * @throws  ParseException If the date params are not valid
     */
  public static Date createDateLocal(int date, int month, int year) throws ParseException {
    return createDateLocal(Integer.toString(date), Integer.toString(month), Integer.toString(year));
  }

    /**
     * Creates a <code>Date</code> representing "now"
     *
     * @return  A <code>Date</code> object that represents "now"
     */
  public static Date getNow() {
    return new Date();
  }

    /**
     * Creates a <code>Date</code> representing "today" (hours and minutes is set to 00:00)
     *
     * @return  A <code>Date</code> object that represents "today"
     */
  public static Date getToday() {
    return removeHourAndMinutes(new Date());
  }


    /**
     * Sets the hours and minutes portion of a <code>Date</code> object to 00:00.
     *
     * @param date  The date to process
     * @return      The <code>Date</code> object that has the hours and minutes set to 00:00
     */
  public static Date removeHourAndMinutes(Date date) {
    return DateUtils.truncate(date, Calendar.DATE);
  }

    /**
     * Gets the <code>Date</code> that represents the "tomorrow" (at midnight) of a given date.
     *
     * @param date  The date to process
     * @return      The <code>Date</code> object that represents the next day
     */
  public static Date getTheNextDayAtMidnight(Date date) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    cal.add(Calendar.DATE, 1);

    Date theNextDay = cal.getTime();
    return removeHourAndMinutes(theNextDay);
  }

    /**
     * Gets the <code>Date</code> that represents the "yesterday" (at midnight) of a given date.
     *
     * @param date  The date to process
     * @return      The <code>Date</code> object that represents the previous day
     */
  public static Date getThePreviousDayAtMidnight(Date date) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    cal.add(Calendar.DATE, -1);

    Date thePreviousDay = cal.getTime();
    return removeHourAndMinutes(thePreviousDay);
  }

  public static Date getThePreviousMonth(Date date,int numOfMonths) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    cal.add(Calendar.MONTH, -numOfMonths);

    Date thePreviousMonth = cal.getTime();
    return removeHourAndMinutes(thePreviousMonth);
  }

  public static Date setDateTime(Date date, int hour, int minute) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, hour);
    cal.set(Calendar.MINUTE, minute);

    return cal.getTime();
  }

  public static Date getBeginningOfMonth(Date date) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    int firstDayOfMonth = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
    cal.set(Calendar.DAY_OF_MONTH, firstDayOfMonth);

    return removeHourAndMinutes(cal.getTime());
  }

  public static Date getEndOfMonth(Date date) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    int firstDayOfMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    cal.set(Calendar.DAY_OF_MONTH, firstDayOfMonth);
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);

    return cal.getTime();
  }

  public static Date getEndOfDay(Date date) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);

    return cal.getTime();
  }

  public static Date getNewDate(Date date,int day) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    cal.set(Calendar.DAY_OF_MONTH, day);

    return removeHourAndMinutes(cal.getTime());
  }

  public static Date getTheNextMonth(Date date,int numOfMonths) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);
    cal.add(Calendar.MONTH, numOfMonths);

    Date theNextMonth = cal.getTime();
    return removeHourAndMinutes(theNextMonth);
  }

  public static int getMonthDiff(Date prevDate,Date currentDate) {
	  long dateDiff = 0;
	  if ( prevDate.getMonth() < currentDate.getMonth()){
		  dateDiff = 12 + prevDate.getMonth()-currentDate.getMonth();
	  }else{
		  dateDiff = currentDate.getMonth()-prevDate.getMonth();
	  }
	  return (int)dateDiff;

  }
	//Added By Meau for Biller
  public static Date substractDate(Date date,int day) {
      Calendar cal = new GregorianCalendar();
      cal.setTime(date);
      cal.add(Calendar.DAY_OF_MONTH, -day);

      Date theNextMonth = cal.getTime();
      return removeHourAndMinutes(theNextMonth);
  }


	//assert: startDate must be before endDate
	public static long getDaysBetween(Date startDate, Date endDate) {

	  Calendar calStartDate = Calendar.getInstance();
	  Calendar calEndDate = Calendar.getInstance();

	  calStartDate.setTime(startDate);
	  calEndDate.setTime(endDate);

	  long daysBetween = 0;
	  while (calStartDate.before(calEndDate)) {
	      calStartDate.add(Calendar.DAY_OF_MONTH, 1);
	    daysBetween++;
	  }
	  return daysBetween;
	}

  public static String getTodayJulianDay() {
	  	Date today = new Date();
        SimpleDateFormat julianDate = new SimpleDateFormat("yyDDD");
        SimpleDateFormat dayOfYear = new SimpleDateFormat("DDD");
        int dayOfYearAsInt;

        return dayOfYear.format(today);
	}

  public static String getFullTodayJulianDay() {
	  	Date today = new Date();
        SimpleDateFormat julianDate = new SimpleDateFormat("DDDyy");
        SimpleDateFormat dayOfYear = new SimpleDateFormat("DDD");
        int dayOfYearAsInt;

        return julianDate.format(today);
	}

}